Skip to content

feat: update 'app link' to not change the app manifest source#396

Merged
mwbrooks merged 8 commits intomainfrom
mwbrooks-default-bolt-manifest-source-local-warnings
Mar 13, 2026
Merged

feat: update 'app link' to not change the app manifest source#396
mwbrooks merged 8 commits intomainfrom
mwbrooks-default-bolt-manifest-source-local-warnings

Conversation

@mwbrooks
Copy link
Member

@mwbrooks mwbrooks commented Mar 13, 2026

Changelog

Updated slack app link command to support project's that use a manifest file as the manifest source (manifest.json).

  • Does not display a warning message when the manifest source is local (project file).
  • Does not change the manifest source - now uses the project's current manifest source.
  • Displays the current manifest source for the developer's reference.
  • Displays a tip on where to change the manifest source (.slack/config.json).

Updated the app manifest overwrite warning prompt wording and appearance.

  • Clarifies that the app settings manifest will be overwritten by the project's app manifest file.
  • Displays a yellow warning that changes were detected on the app settings manifest that are not in the project's app manifest file.

Summary

This pull request is a little spicy 🌶️ because remove speed bumps and reduces friction for developers to allows apps from App setting to be managed by the Slack CLI.

See Changelog section for a detailed breakdown of the changes.

Motivation

The motivation for these changes is 💬 developer feedback. A consistent theme of questions from developers is how to have the Slack CLI manage and use the manifest.json that ships with all of our sample apps (sensible question). We often need to explain how to manually update .slack/config.json → manifest.source: "local" for developers to get the experience they want.

Our concern for embracing the project's manifest file is that it can overwrite the manifest on App Settings. This could be a shocking and difficult experience, if it happens unexpectedly. Thankfully, the Slack CLI's overwrite protection has been reliable for the past year and this change leans more heavily on it.

Preview

Linking an App ID from App Setting

Currently, when Linking an App ID from App Setting, the developer is forced to switch the manifest source to be App Setting (remote). If they decline the confirmation prompt, then they cannot link the app. A workaround that developers have taken is to accept the confirmation and then manually change the manifest source back to the manifest file: .slack/config → manifest.source: "local".

Now, the manifest source is not changed - it can remain local (manifest file) or remote (app settings). We rely on the manifest overwrite protection to warn developers when there are changes on App Settings that are not in the manifest file.

Expand to see a video of the current behaviour
2026-03-13-app-link-current.mov
2026-03-13-app-link-new.mov

Overwriting App Settings Warning

We made minor wording and appearance changes to clarify that the app settings manifest will be overwritten by the manifest file.

Expand to see a video of the current behaviour
2026-03-13-overwrite-manifest-current.mov
2026-03-13-overwrite-manifest-new.mov

Test Steps

# Create a Bolt Framework project
$ lack create my-app -t https://github.com/slack-samples/bolt-js-starter-template.git
$ cd my-app/

# Start & Stop the dev server to create an App ID 
$ lack run
# → Create an app
# → Stop the server once it's running
# CTRL+C

# Copy the App ID
$ lack app list
# → Copy the App ID

# Unlink the App ID
$ lack app unlink
# → Select your App ID

# Test: App Link
$ lack app link
# → Confirm: "Manifest source is "project" (local)"
# → Confirm: "Manifest source is configured in .slack/config.json"
# → App ID: Paste the App ID
# → Environment: Local

# Test: Change App Settings
$ lack app settings
# → Add a short description
# → Add a background color
# → Save

# Test: Overwrite Warning
$ lack run
# → Confirm: Overwrite warning
# → Select "Y"
# → CTRL+C after dev server starts

# Test: Confirm No Overwrite Warning when Manifests In-Sync
$ lack run
# → Confirm: No warning and dev server starts
# → CTRL+C

# Clean up
$ lack delete -f
$ cd ..
$ rm -rf my-app/

Requirements

Change the default manifest source for non-Deno (Bolt) projects from
ManifestSourceRemote to ManifestSourceLocal, aligning their behavior
with Deno projects.
@mwbrooks mwbrooks changed the title feat: update app manifest warnings for 'app link' and manifest overwrite prompt feat: update 'app link' to not change the app manifest source Mar 13, 2026
@codecov
Copy link

codecov bot commented Mar 13, 2026

Codecov Report

❌ Patch coverage is 84.61538% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.90%. Comparing base (3744b76) to head (aa2a95a).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
cmd/app/link.go 81.81% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #396      +/-   ##
==========================================
- Coverage   67.90%   67.90%   -0.01%     
==========================================
  Files         218      218              
  Lines       18085    18050      -35     
==========================================
- Hits        12281    12256      -25     
+ Misses       4651     4640      -11     
- Partials     1153     1154       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mwbrooks mwbrooks self-assigned this Mar 13, 2026
@mwbrooks mwbrooks added enhancement M-T: A feature request for new functionality changelog Use on updates to be included in the release notes semver:minor Use on pull requests to describe the release version increment area:bolt-js Related to github.com/slackapi/bolt-js area:bolt-python Related to github.com/slackapi/bolt-python labels Mar 13, 2026
@mwbrooks mwbrooks added this to the Next Release milestone Mar 13, 2026
Copy link
Member Author

@mwbrooks mwbrooks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some words for the kind reviewers!

cmd/app/link.go Outdated
// App Manifest section
manifestSource, _ := clients.Config.ProjectConfig.GetManifestSource(ctx)
if !manifestSource.Exists() {
manifestSource = config.ManifestSourceLocal
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note(out-of-scope): We should have the default manifest source return by a common method instead of manually setting it in each spot.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🪬 question: I notice that without a source attribute in configs we default to a local manifest. Is this something we can favor instead of writing settings to projects?

👾 note: I realize a saved value in each project settings file means less confusion toward defaults, but IMHO we might have paths toward extending the "local" manifest experience adjacent.

// GetManifestSource finds the manifest source preference for the project
func (c *ProjectConfig) GetManifestSource(ctx context.Context) (ManifestSource, error) {
var span opentracing.Span
span, ctx = opentracing.StartSpanFromContext(ctx, "GetManifestSource")
defer span.Finish()
var projectConfig, err = ReadProjectConfigFile(ctx, c.fs, c.os)
if err != nil {
return "", err
}
if projectConfig.Manifest != nil {
source := ManifestSource(strings.TrimSpace(projectConfig.Manifest.Source))
switch {
case source.Equals(ManifestSourceLocal), source.Equals(ManifestSourceRemote):
return source, nil
case !source.Exists():
return ManifestSourceLocal, nil
default:
return "", slackerror.New(slackerror.ErrProjectConfigManifestSource)
}
}
return ManifestSourceLocal, nil
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. My feeling is that - for now - we should explicitly write to the config.json to ensure that a project functions the way it's expected even if the CLI changes it's defaults.

However, I see where you're coming from. I also know we juggle some challenges with config.json in templates (e.g. Project ID). Perhaps your ideas would have address those?

ExpectedError: slackerror.New(slackerror.ErrAppNotFound),
},
"accepting manifest source prompt should save information about the provided deployed app": {
"links app when manifest source is local": {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: Test linking an app when the manifest source is local (manifest file).

},
},
"manifest source prompt should display for GBP apps with local manifest source": {
"links app when manifest source is remote": {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: Test linking an app when the manifest source is remote (app settings).

notice = "Manifest values for this app are overwritten on reinstall"
default:
notice = "The manifest on app settings has been changed since last update!"
notice = style.Yellow("The manifest on app settings has been changed since last update")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: I'm open to other formatting (Red?) but I think we should make this pop and stand out in some way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌟 praise: I like yellow: it matches error codes and isn't confusing with green! But we might continue these discussions in a style guide soonish-

@mwbrooks mwbrooks marked this pull request as ready for review March 13, 2026 17:27
@mwbrooks mwbrooks requested a review from a team as a code owner March 13, 2026 17:27
Copy link
Member

@zimeg zimeg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mwbrooks So amazing! I'm leaving more comments that suggest we find a source of truth in configuration defaults, but that shouldn't be blocking. I like the improvements to outputs you're making with these changes a lot 🎨 ✨

cmd/app/link.go Outdated
// App Manifest section
manifestSource, _ := clients.Config.ProjectConfig.GetManifestSource(ctx)
if !manifestSource.Exists() {
manifestSource = config.ManifestSourceLocal
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🪬 question: I notice that without a source attribute in configs we default to a local manifest. Is this something we can favor instead of writing settings to projects?

👾 note: I realize a saved value in each project settings file means less confusion toward defaults, but IMHO we might have paths toward extending the "local" manifest experience adjacent.

// GetManifestSource finds the manifest source preference for the project
func (c *ProjectConfig) GetManifestSource(ctx context.Context) (ManifestSource, error) {
var span opentracing.Span
span, ctx = opentracing.StartSpanFromContext(ctx, "GetManifestSource")
defer span.Finish()
var projectConfig, err = ReadProjectConfigFile(ctx, c.fs, c.os)
if err != nil {
return "", err
}
if projectConfig.Manifest != nil {
source := ManifestSource(strings.TrimSpace(projectConfig.Manifest.Source))
switch {
case source.Equals(ManifestSourceLocal), source.Equals(ManifestSourceRemote):
return source, nil
case !source.Exists():
return ManifestSourceLocal, nil
default:
return "", slackerror.New(slackerror.ErrProjectConfigManifestSource)
}
}
return ManifestSourceLocal, nil
}

cmd/app/link.go Outdated
Comment on lines 155 to 157
if !manifestSource.Exists() {
manifestSource = config.ManifestSourceLocal
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if !manifestSource.Exists() {
manifestSource = config.ManifestSourceLocal
}

🪬 quibble: Related to the comment above, this might be alright to remove?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great suggestion! Commit b1b2678 in PR #395 now leverages the defaults provided by the project config getter. I think we can do the same here. I'll look into it now 🔍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit 0f2e6e1 removes this check 🎉

notice = "Manifest values for this app are overwritten on reinstall"
default:
notice = "The manifest on app settings has been changed since last update!"
notice = style.Yellow("The manifest on app settings has been changed since last update")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌟 praise: I like yellow: it matches error codes and isn't confusing with green! But we might continue these discussions in a style guide soonish-

Comment on lines +159 to +166
clients.IO.PrintInfo(ctx, false, "%s", style.Sectionf(style.TextSection{
Emoji: "books",
Text: "App Manifest",
Secondary: []string{
"Manifest source is " + style.Highlight(manifestSource.Human()),
"Manifest source is configured in " + style.Highlight(configPath),
},
}))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧭 praise: This is a nice callout to new learnings in this experience! I'm not certain how familiar the local|remote manifest concept is to exploring developers.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It crossed my mind as well and we don't have formal documentation that we can point toward. I figured I'd leave it as a future task for now.

Base automatically changed from mwbrooks-default-bolt-manifest-source-local to main March 13, 2026 21:27
@mwbrooks
Copy link
Member Author

Thanks for the review and suggested improvements @zimeg! I think this is a step forward and we may have some new ideas on improving the project's config.json from our discussion! 🙇🏻

@mwbrooks mwbrooks merged commit 265d8a9 into main Mar 13, 2026
7 checks passed
@mwbrooks mwbrooks deleted the mwbrooks-default-bolt-manifest-source-local-warnings branch March 13, 2026 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:bolt-js Related to github.com/slackapi/bolt-js area:bolt-python Related to github.com/slackapi/bolt-python changelog Use on updates to be included in the release notes enhancement M-T: A feature request for new functionality semver:minor Use on pull requests to describe the release version increment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants